package com.aliang.chat.controller;

import cn.hutool.json.JSONUtil;
import com.aliang.chat.model.dto.ContactDTO;
import com.aliang.chat.model.dto.MessageDTO;
import com.aliang.chat.service.ContactService;
import com.aliang.chat.service.MessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")  // 接口路径 ws://localhost:8087/webSocket/userId;
public class WebSocket {

    @Autowired
    private MessageService messageService;
    @Autowired
    private ContactService contactService;

    private static WebSocket socket;

    @PostConstruct
    public void init(){
        socket = this;
        socket.messageService = this.messageService;
        socket.contactService = this.contactService;
    }
    
    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
        /**
     * 用户ID
     */
    private Integer userId;
    
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    //虽然@Component默认是单例模式的，但springboot还是会为每个websocket连接初始化一个bean，所以可以用一个静态set保存起来。
    //  注：底下WebSocket是当前类名
    private static CopyOnWriteArraySet<WebSocket> webSockets =new CopyOnWriteArraySet<>();
    // 用来存在线连接用户信息
    private static final ConcurrentHashMap<Integer,Session> sessionPool = new ConcurrentHashMap<Integer,Session>();

    
    /**
     * 链接成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value="userId")Integer userId) {
        try {
            this.session = session;
            this.userId = userId;
            webSockets.add(this);
            sessionPool.put(userId, session);
            log.info("【websocket消息】有新的连接，总数为:"+webSockets.size());
        } catch (Exception e) {
            log.error("连接异常，异常信息：{}",e.getMessage());
        }
    }
    
    /**
     * 链接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        try {
            webSockets.remove(this);
            sessionPool.remove(this.userId);
            log.info("【websocket消息】连接断开，总数为:"+webSockets.size());
        } catch (Exception e) {
        }
    }
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(Session session,String message) {
        if (message.contains("type")) {
            MessageDTO messageDTO = JSONUtil.toBean(message, MessageDTO.class);
            // 保存消息
            messageDTO.setStatus("success");
            System.out.println(messageDTO);
            socket.messageService.addMessage(messageDTO);
           session.getAsyncRemote().sendText(JSONUtil.toJsonStr(messageDTO));
           sendOneMessage(messageDTO.getToContactId(),JSONUtil.toJsonStr(messageDTO));
        } else if (message.contains("unread")) {
            //添加或者更新用户数据
            ContactDTO contactDTO = JSONUtil.toBean(message, ContactDTO.class);
            socket.contactService.addOrUpdateContact(contactDTO,this.userId);
        }
    }

    /** 发送错误时的处理
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误,原因:"+error.getMessage());
        error.printStackTrace();
    }

    
    // 此为广播消息
    public void sendAllMessage(String message) {
        log.info("【websocket消息】广播消息:"+message);
        for(WebSocket webSocket : webSockets) {
            try {
                if(webSocket.session.isOpen()) {
                    webSocket.session.getAsyncRemote().sendText(message);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    // 此为单点消息
    public void sendOneMessage(Integer userId, String message) {
        Session session = sessionPool.get(userId);
        if (session != null&&session.isOpen()) {
            try {
                log.info("【websocket消息】 单点消息:"+message);
                session.getAsyncRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    // 此为单点消息(多人)
    public void sendMoreMessage(Integer[] userIds, String message) {
        for(Integer userId:userIds) {
            Session session = sessionPool.get(userId);
            if (session != null&&session.isOpen()) {
                try {
                    log.info("【websocket消息】 单点消息:"+message);
                    session.getAsyncRemote().sendText(message);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        
    }
    
}